package com.dmcb.common.business.utils;

import net.sf.json.JSONObject;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.net.ssl.*;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.zip.GZIPInputStream;

/**
 * Created by a on 2015/3/12.
 */
public class WebUtil {

    protected static final Logger logger = LoggerFactory.getLogger(WebUtil.class);
    private static final int PORT = 3128;



    public static String URLEncode(String s) {
        return URLEncode(s, "");
    }

    /**
     * URL编码
     *
     * @param s
     * @param encoding
     * @return
     */
    public static String URLEncode(String s, String encoding) {
        if (StringUtils.isBlank(encoding)) {
            encoding = "utf-8";
        }
        try {
            return java.net.URLEncoder.encode(s, encoding);
        } catch (Exception e) {
            return s;
        }
    }

    public static String URLDecode(String s) {
        return URLDecode(s, "");
    }

    /**
     * URL解码
     *
     * @param s
     * @param encoding
     * @return
     */
    public static String URLDecode(String s, String encoding) {
        if (StringUtils.isBlank(encoding)) {
            encoding = "utf-8";
        }
        try {
            return java.net.URLDecoder.decode(s, encoding);
        } catch (Exception e) {
            return s;
        }
    }

    /**
     * 建立请求
     *
     * @return 结果
     */
    public static String buildRequest(String link, boolean isProxy) {
        HttpClient client;
        if(isProxy){
            client = getClient();
        }else{
            client = new HttpClient();
        }
        HttpMethod method = null;
        try {
            method = new GetMethod(link);
            client.executeMethod(method);
            InputStream inputStream = method.getResponseBodyAsStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            StringBuilder stringBuilder = new StringBuilder();
            String str;
            while ((str = br.readLine()) != null) {
                stringBuilder.append(str);
            }
            return stringBuilder.toString();
        } catch (Exception e) {
            logger.error("buildRequest error, link={}", link, e);
            return "";
        } finally {
            //释放连接
            if (method != null) {
                method.releaseConnection();
            }
        }
    }

    /**
     * 建立请求
     * header有参数
     *
     * @return 结果
     */
    public static String buildRequestData2(String link,boolean isProxy, Map<String, String> map) {
        HttpClient client ;
        if(isProxy){
            client = getClient();
        }else{
            client = new HttpClient();
        }
        HttpMethod method = null;
        return getString(link, map, client, method);
    }


    private static String getdata(InputStream inputStream, HttpMethod method) throws IOException {
        InputStreamReader isr =new InputStreamReader(inputStream, "UTF-8");
        Header[] headers =  method.getRequestHeaders();
        isr = getInputStreamReader(inputStream, isr, headers);
        BufferedReader br = new BufferedReader(isr);
        StringBuilder stringBuilder = new StringBuilder();
        String str;
        while ((str = br.readLine()) != null) {
            stringBuilder.append(str);
        }
        return stringBuilder.toString();
    }

    //从该博客找到的解决方案，网站都先将网页压缩后再传回给浏览器，所以得用GZIPInputStream对数据流进行处理 https://blog.csdn.net/u012465296/article/details/53036205
    private static InputStreamReader getInputStreamReader(InputStream inputStream, InputStreamReader isr, Header[] headers) {
        for(Header h : headers){
            if(h.getValue().indexOf("gzip") > -1){
                //For GZip response
                try{
                    GZIPInputStream gzin = new GZIPInputStream(inputStream);
                    isr = new InputStreamReader(gzin,"utf-8");
                }catch (IOException exception){
                    exception.printStackTrace();
                }
                break;
            }
        }
        return isr;
    }


    /**
     * 建立请求
     *
     * @return 结果
     */
    public static HttpClient getClient() {
        HttpClient client = new HttpClient();
        String host = JedisHelper.getIp(WebClientUtil.PROXY_REGION);
        client.getHostConfiguration().setProxy(host, PORT);
        client.getParams().setAuthenticationPreemptive(true);
        //如果代理需要密码验证，这里设置用户名密码
        client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials("kbanquan", "kb102210"));
        return client;
    }


    /**
     * 建立请求
     *
     * @return 结果
     */
    public static String postRequest(String link, boolean isProxy, Map<String, String> map) {
        HttpClient client;
        if(isProxy){
            client = getClient();
        }else{
            client = new HttpClient();
        }
        HttpMethod method = null;
        try {
            method = new PostMethod(link);
            if (map != null) {
                for (String key : map.keySet()) {
                    method.addRequestHeader(key, map.get(key));
                }
            }
            client.executeMethod(method);
            InputStream inputStream = method.getResponseBodyAsStream();
            return getdata(inputStream,method);
        } catch (Exception e) {
            logger.error("buildRequest error, link={}", link, e);
            return "";
        } finally {
            //释放连接
            if (method != null) {
                method.releaseConnection();
            }
        }
    }

    /**
     * 建立请求
     * header有参数
     *
     * @return 结果
     */
    public static String buildRequestData(String link,boolean isProxy, Map<String, String> map) {
        HttpClient client ;
        if(isProxy){
            client = getClient();
        }else{
            client = new HttpClient();
        }
        HttpMethod method = null;
        return getString(link, map, client, method);
    }

    private static String getString(String link, Map<String, String> map, HttpClient client, HttpMethod method) {
        try {
            method = new GetMethod(link);
            if (map != null) {
                for (String key : map.keySet()) {
                    method.addRequestHeader(key, map.get(key));
                }
            }
            client.executeMethod(method);
            InputStream inputStream = method.getResponseBodyAsStream();
            return getdata(inputStream,method);
        } catch (Exception e) {
            logger.error("buildRequest error, link={}", link, e);
            return "";
        } finally {
            //释放连接
            if (method != null) {
                method.releaseConnection();
            }
        }
    }

    /**
     * 忽视证书HostName
     */
    private static HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
        public boolean verify(String s, SSLSession sslsession) {
            System.out.println("WARNING: Hostname is not matched for cert.");
            return true;
        }
    };


    /**
     * Ignore Certification
     */
    private static TrustManager ignoreCertificationTrustManger = new X509TrustManager() {
        private X509Certificate[] certificates;

        @Override
        public void checkClientTrusted(X509Certificate certificates[],
                                       String authType) throws CertificateException {
            if (this.certificates == null) {
                this.certificates = certificates;
                System.out.println("init at checkClientTrusted");
            }
        }


        @Override
        public void checkServerTrusted(X509Certificate[] ax509certificate,
                                       String s) throws CertificateException {
            if (this.certificates == null) {
                this.certificates = ax509certificate;
                System.out.println("init at checkServerTrusted");
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    public static String buildRequestIgnoreSSL(String urlString) {
        org.apache.commons.io.output.ByteArrayOutputStream buffer = new org.apache.commons.io.output.ByteArrayOutputStream(512);
        try {
            URL url = new URL(urlString);
            /*
             * use ignore host name verifier
             */
            HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            // Prepare SSL Context
            TrustManager[] tm = {ignoreCertificationTrustManger};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            connection.setSSLSocketFactory(ssf);

            InputStream reader = connection.getInputStream();
            byte[] bytes = new byte[512];
            int length = reader.read(bytes);
            do {
                buffer.write(bytes, 0, length);
                length = reader.read(bytes);
            } while (length > 0);
            reader.close();
            connection.disconnect();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
        }
        String repString = new String(buffer.toByteArray());
        return repString;
    }



    public static String buildRequestIgnoreSSL2(String urlString,Map<String,String> map) {
        org.apache.commons.io.output.ByteArrayOutputStream buffer = new org.apache.commons.io.output.ByteArrayOutputStream(512);
        String repString = "";
        try {
            URL url = new URL(urlString);
            /*
             * use ignore host name verifier
             */
            HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
            for(String key : map.keySet()){
                connection.setRequestProperty(key,map.get(key));
            }
            // Prepare SSL Context
            TrustManager[] tm = {ignoreCertificationTrustManger};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            connection.setSSLSocketFactory(ssf);

            //读取响应
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String lines;
            StringBuffer sb = new StringBuffer("");
            while ((lines = reader.readLine()) != null) {
                lines = new String(lines.getBytes());
                sb.append(lines);
            }
            reader.close();
            connection.disconnect();
            return sb.toString();
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }

    }



    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！" + e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            iOClose(out, in);
        }
        return result;
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @param map   请求的头部信息
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param, Map<String, String> map) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            if (map != null) {
                for (String key : map.keySet()) {
                    conn.setRequestProperty(key, map.get(key));
                }
            }
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！" + e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            iOClose(out, in);
        }
        return result;
    }

    private static void iOClose(PrintWriter out, BufferedReader in) {
        try {
            if (out != null) {
                out.close();
            }
            if (in != null) {
                in.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 建立请求
     *
     * @return 结果
     */
    public static InputStream getImageStream(String link) {
        if (StringUtils.isBlank(link)) {
            return null;
        }
        try {
            GetMethod method = new GetMethod(link);
            new HttpClient().executeMethod(method);
            return method.getResponseBodyAsStream();
        } catch (Exception e) {
            logger.error("buildRequestImage error, link={}", link, e);
            return null;
        }
    }

    /**
     * 建立请求
     *
     * @return 结果
     */
    public static BufferedImage buildRequestImage(String link) {
        InputStream inputStream = getImageStream(link);
        try {
            return inputStream == null ? null : ImageIO.read(inputStream);
        } catch (Exception e) {
            logger.error("buildRequestImage error, link={}", link, e);
            return null;
        }
    }

    public static String getRemoteIP(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }


    /**
     * @param link 请求的链接
     * @param map  参数的集合
     * @param head 头部 Content-Type的信息，以后头部需要的多，可以写成map
     */
    public static String sendJsonPost(String link, Map<String, String> map, String head) {
        try {
            //创建连接
            URL url = new URL(link);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", head);
            connection.connect();
            //POST请求
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            JSONObject obj = new JSONObject();
            for (String key : map.keySet()) {
                obj.element(key, map.get(key));
            }
            out.writeBytes(obj.toString());
            out.flush();
            out.close();

            //读取响应
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String lines;
            StringBuffer sb = new StringBuffer("");
            while ((lines = reader.readLine()) != null) {
                lines = new String(lines.getBytes(), "utf-8");
                sb.append(lines);
            }
            reader.close();
            // 断开连接
            connection.disconnect();
            return sb.toString();
        } catch (Exception e) {
         return e.getMessage();
        }

    }
    /**
     * 获取重定向地址
     * @param path
     * @return
     * @throws Exception
     */
    public static  String getRedirectUrl(String path) throws Exception {
        HttpURLConnection conn = (HttpURLConnection) new URL(path)
                .openConnection();
        conn.setInstanceFollowRedirects(false);
        conn.setConnectTimeout(5000);
        return conn.getHeaderField("location");
    }


    /*
     * unicode编码转中文
     */
    public static String decodeUnicode(final String dataStr) {
        int start = 0;
        int end = 0;
        final StringBuffer buffer = new StringBuffer();
        while (start > -1) {
            end = dataStr.indexOf("\\u", start + 2);
            String charStr = "";
            if (end == -1) {
                charStr = dataStr.substring(start + 2, dataStr.length());
            } else {
                charStr = dataStr.substring(start + 2, end);
            }
            char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
            buffer.append(new Character(letter).toString());
            start = end;
        }
        return buffer.toString();
    }
}
